Skip to content

Method: generateVocabulary(OWLOntology, ContextDefinition, String, String, boolean)

1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: * <p>
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: * <p>
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.owl2java;
16:
17: import com.sun.codemodel.JAnnotationArrayMember;
18: import com.sun.codemodel.JAnnotationUse;
19: import com.sun.codemodel.JClass;
20: import com.sun.codemodel.JClassAlreadyExistsException;
21: import com.sun.codemodel.JCodeModel;
22: import com.sun.codemodel.JDefinedClass;
23: import com.sun.codemodel.JDocComment;
24: import com.sun.codemodel.JExpr;
25: import com.sun.codemodel.JFieldRef;
26: import com.sun.codemodel.JFieldVar;
27: import com.sun.codemodel.JMethod;
28: import com.sun.codemodel.JMod;
29: import com.sun.codemodel.JType;
30: import com.sun.codemodel.JVar;
31: import cz.cvut.kbss.jopa.CommonVocabulary;
32: import cz.cvut.kbss.jopa.ic.api.AtomicSubClassConstraint;
33: import cz.cvut.kbss.jopa.ic.api.DataParticipationConstraint;
34: import cz.cvut.kbss.jopa.ic.api.ObjectParticipationConstraint;
35: import cz.cvut.kbss.jopa.model.annotations.Id;
36: import cz.cvut.kbss.jopa.model.annotations.OWLAnnotationProperty;
37: import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty;
38: import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty;
39: import cz.cvut.kbss.jopa.model.annotations.ParticipationConstraint;
40: import cz.cvut.kbss.jopa.model.annotations.ParticipationConstraints;
41: import cz.cvut.kbss.jopa.model.annotations.Properties;
42: import cz.cvut.kbss.jopa.model.annotations.Sequence;
43: import cz.cvut.kbss.jopa.model.annotations.SequenceType;
44: import cz.cvut.kbss.jopa.model.annotations.Types;
45: import static cz.cvut.kbss.jopa.owl2java.Constants.*;
46: import cz.cvut.kbss.jopa.owlapi.DatatypeTransformer;
47: import java.io.File;
48: import java.io.IOException;
49: import java.util.Arrays;
50: import java.util.Collection;
51: import java.util.HashMap;
52: import java.util.HashSet;
53: import java.util.Map;
54: import java.util.Set;
55: import org.semanticweb.owlapi.model.IRI;
56: import org.semanticweb.owlapi.model.OWLAnnotation;
57: import org.semanticweb.owlapi.model.OWLClass;
58: import org.semanticweb.owlapi.model.OWLEntity;
59: import org.semanticweb.owlapi.model.OWLLiteral;
60: import org.semanticweb.owlapi.model.OWLOntology;
61: import org.slf4j.Logger;
62: import org.slf4j.LoggerFactory;
63:
64: public class JavaTransformer {
65:
66: private static final Logger LOG = LoggerFactory.getLogger(OWL2JavaTransformer.class);
67:
68: private static final String[] KEYWORDS = {"abstract",
69: "assert",
70: "boolean",
71: "break",
72: "byte",
73: "case",
74: "catch",
75: "char",
76: "class",
77: "const",
78: "continue",
79: "default",
80: "do",
81: "double",
82: "else",
83: "enum",
84: "extends",
85: "final",
86: "finally",
87: "float",
88: "for",
89: "goto",
90: "if",
91: "implements",
92: "import",
93: "instanceof",
94: "int",
95: "interface",
96: "long",
97: "native",
98: "new",
99: "package",
100: "private",
101: "protected",
102: "public",
103: "return",
104: "short",
105: "static",
106: "strictfp",
107: "super",
108: "switch",
109: "synchronized",
110: "this",
111: "throw",
112: "throws",
113: "transient",
114: "try",
115: "void",
116: "volatile",
117: "while"};
118:
119: private JDefinedClass voc;
120: private Map<OWLEntity, JFieldRef> entities = new HashMap<>();
121:
122: private Map<OWLClass, JDefinedClass> classes = new HashMap<>();
123:
124: private static String validJavaIDForIRI(final IRI iri) {
125: if (iri.getFragment() != null) {
126: return validJavaID(iri.getFragment());
127: } else {
128: int x = iri.toString().lastIndexOf("/");
129: return validJavaID(iri.toString().substring(x + 1));
130: }
131: }
132:
133: private static String validJavaID(final String s) {
134: String res = s.trim().replace("-", "_").replace("'", "_quote_").replace(".", "_dot_").replace(',', '_');
135: if (Arrays.binarySearch(KEYWORDS, res) >= 0) {
136: res = "_" + res;
137: }
138: return res;
139: }
140:
141: private JFieldVar addField(final String name, final JDefinedClass cls,
142: final JType fieldType) {
143: String newName = name;
144:
145: int i = 0;
146: while (cls.fields().containsKey(newName)) {
147: newName = name + "" + (++i);
148: }
149:
150: final JFieldVar fvId = cls.field(JMod.PROTECTED, fieldType, newName);
151: final String fieldName = fvId.name().substring(0, 1).toUpperCase() + fvId.name().substring(1);
152: final JMethod mSetId = cls.method(JMod.PUBLIC, void.class, "set" + fieldName);
153: final JVar v = mSetId.param(fieldType, fvId.name());
154: mSetId.body().assign(JExpr._this().ref(fvId), v);
155: final JMethod mGetId = cls.method(JMod.PUBLIC, fieldType, "get" + fieldName);
156: mGetId.body()._return(fvId);
157: return fvId;
158: }
159:
160: public void generateModel(final OWLOntology ontology,
161: final ContextDefinition context, final String pkg, String targetDir, boolean withOWLAPI) {
162:
163: try {
164: final JCodeModel cm = new JCodeModel();
165: voc = cm._class(pkg + PACKAGE_SEPARATOR + VOCABULARY_CLASS);
166: generateVocabulary(ontology, cm, context, withOWLAPI);
167: _generateModel(ontology, cm, context, pkg + PACKAGE_SEPARATOR + MODEL_PACKAGE + PACKAGE_SEPARATOR);
168: writeOutModel(cm, targetDir);
169: } catch (JClassAlreadyExistsException e1) {
170: LOG.error("Transformation FAILED.", e1);
171: } catch (IOException e) {
172: LOG.error("File generation FAILED.", e);
173: }
174: }
175:
176: /**
177: * Generates only vocabulary of the loaded ontology.
178: *
179: * @param ontology Ontology from which the vocabulary should be generated
180: * @param context Integrity constraints context, if null is supplied, the whole ontology is interpreted as
181: * integrity constraints.
182: * @param targetDir Directory into which the vocabulary file will be generated
183: * @param pkg Package
184: * @param withOWLAPI Whether OWLAPI-based IRIs of the generated vocabulary items should be created as well
185: */
186: public void generateVocabulary(final OWLOntology ontology, ContextDefinition context, String pkg, String targetDir,
187: boolean withOWLAPI) {
188: try {
189: final JCodeModel cm = new JCodeModel();
190: this.voc = cm._class(pkg + PACKAGE_SEPARATOR + VOCABULARY_CLASS);
191: generateVocabulary(ontology, cm, context, withOWLAPI);
192: writeOutModel(cm, targetDir);
193: } catch (JClassAlreadyExistsException e) {
194: LOG.error("Vocabulary generation FAILED, because the Vocabulary class already exists.", e);
195: } catch (IOException e) {
196: LOG.error("Vocabulary file generation FAILED.", e);
197: }
198: }
199:
200: private void writeOutModel(JCodeModel cm, String targetDir) throws IOException {
201: final File file = new File(targetDir);
202: file.mkdirs();
203: cm.build(file);
204: }
205:
206: private void _generateObjectProperty(final OWLOntology ontology,
207: final JCodeModel cm,
208: final ContextDefinition context,
209: final String pkg,
210: final OWLClass clazz,
211: final JDefinedClass subj,
212: final org.semanticweb.owlapi.model.OWLObjectProperty prop) {
213: final ClassObjectPropertyComputer comp = new ClassObjectPropertyComputer(
214: clazz,
215: prop,
216: context.set,
217: ontology
218: );
219:
220: if (!Card.NO.equals(comp.getCard())) {
221: JClass filler = ensureCreated(context, pkg, cm,
222: comp.getFiller(), ontology);
223: final String fieldName = validJavaIDForIRI(prop.getIRI());
224:
225: switch (comp.getCard()) {
226: case ONE:
227: break;
228: case MULTIPLE:
229: filler = cm.ref(java.util.Set.class).narrow(filler);
230: break;
231: case SIMPLELIST:
232: case LIST:
233: filler = cm.ref(java.util.List.class).narrow(filler);
234: break;
235: }
236:
237: final JFieldVar fv = addField(fieldName, subj, filler);
238:
239: if (comp.getCard().equals(Card.SIMPLELIST)) {
240: fv.annotate(Sequence.class)
241: .param("type", SequenceType.simple);
242: }
243:
244:
245: fv.annotate(OWLObjectProperty.class).param("iri",
246: entities.get(prop));
247:
248: JAnnotationArrayMember use = null;
249: for (ObjectParticipationConstraint ic : comp
250: .getParticipationConstraints()) {
251: if (use == null) {
252: use = fv.annotate(ParticipationConstraints.class)
253: .paramArray("value");
254: }
255: JAnnotationUse u = use.annotate(
256: ParticipationConstraint.class).param(
257: // "owlClassIRI",
258: // ic.getSubject().getIRI().toString()).param(
259: // "owlPropertyIRI",
260: // ic.getPredicate().getIRI().toString()).param(
261: "owlObjectIRI", entities.get(ic.getObject()));
262: if (ic.getMin() != 0) {
263: u.param("min", ic.getMin());
264: }
265:
266: if (ic.getMax() != -1) {
267: u.param("max", ic.getMax());
268: }
269: }
270: }
271: }
272:
273: private void _generateDataProperty(final OWLOntology ontology,
274: final JCodeModel cm,
275: final ContextDefinition context,
276: final String pkg,
277: final OWLClass clazz,
278: final JDefinedClass subj,
279: final org.semanticweb.owlapi.model.OWLDataProperty prop) {
280: final ClassDataPropertyComputer comp = new ClassDataPropertyComputer(
281: clazz,
282: prop,
283: context.set,
284: ontology
285: );
286:
287: if (!Card.NO.equals(comp.getCard())) {
288:
289: final JType obj = cm._ref(DatatypeTransformer
290: .transformOWLType(comp.getFiller()));
291:
292: final String fieldName = validJavaIDForIRI(
293: prop.getIRI());
294:
295: JFieldVar fv;
296:
297: if (Card.MULTIPLE.equals(comp.getCard())) {
298: fv = addField(fieldName, subj, cm.ref(java.util.Set.class)
299: .narrow(obj));
300: } else if (Card.ONE.equals(comp.getCard())) {
301: fv = addField(fieldName, subj, obj);
302: } else {
303: assert false : "Unknown cardinality type";
304: return;
305: }
306:
307: fv.annotate(OWLDataProperty.class).param("iri",
308: entities.get(prop));
309:
310: JAnnotationArrayMember use = null;
311: for (DataParticipationConstraint ic : comp
312: .getParticipationConstraints()) {
313: if (use == null) {
314: use = fv.annotate(ParticipationConstraints.class)
315: .paramArray("value");
316: }
317:
318: JAnnotationUse u = use.annotate(
319: ParticipationConstraint.class).param(
320: "owlObjectIRI", comp.getFiller().getIRI().toString());
321:
322: if (ic.getMin() != 0) {
323: u = u.param("min", ic.getMin());
324: }
325:
326: if (ic.getMax() != -1) {
327: u = u.param("max", ic.getMax());
328: }
329: }
330: }
331: }
332:
333: private void _generateModel(final OWLOntology ontology, final JCodeModel cm,
334: final ContextDefinition context, final String pkg) {
335: LOG.info("Generating model ...");
336:
337: context.classes.add(ontology.getOWLOntologyManager().getOWLDataFactory().getOWLThing());
338:
339: for (final OWLClass clazz : context.classes) {
340: LOG.info(" Generating class '{}'.", clazz);
341: final JDefinedClass subj = ensureCreated(context, pkg, cm, clazz, ontology);
342:
343: context.set.getClassIntegrityConstraints(clazz).forEach((ic) -> {
344: if (ic instanceof AtomicSubClassConstraint) {
345: final AtomicSubClassConstraint icc = (AtomicSubClassConstraint) ic;
346: subj._extends(ensureCreated(context, pkg, cm, icc.getSupClass(), ontology));
347: }
348: });
349:
350: for (final org.semanticweb.owlapi.model.OWLObjectProperty prop : context.objectProperties) {
351: _generateObjectProperty(ontology, cm, context, pkg, clazz, subj, prop);
352: }
353:
354: for (org.semanticweb.owlapi.model.OWLDataProperty prop : context.dataProperties) {
355: _generateDataProperty(ontology, cm, context, pkg, clazz, subj, prop);
356: }
357: }
358: }
359:
360: private void generateVocabulary(final OWLOntology o, final JCodeModel cm, ContextDefinition context,
361: boolean withOWLAPI) {
362: final Collection<OWLEntity> col = new HashSet<>();
363: col.add(o.getOWLOntologyManager().getOWLDataFactory().getOWLThing());
364: col.addAll(context.classes);
365: col.addAll(context.objectProperties);
366: col.addAll(context.dataProperties);
367: col.addAll(context.annotationProperties);
368: col.addAll(context.individuals);
369:
370: for (final OWLOntology s : o.getOWLOntologyManager().getOntologies()) {
371: IRI iri = s.getOntologyID().getOntologyIRI();
372: voc.field(JMod.PUBLIC | JMod.STATIC
373: | JMod.FINAL, String.class, "ONTOLOGY_IRI_" + validJavaIDForIRI(iri),
374: JExpr.lit(iri.toString()));
375: }
376:
377: for (final OWLEntity c : col) {
378: String prefix = "";
379:
380: if (c.isOWLClass()) {
381: prefix = "c_";
382: } else if (c.isOWLDatatype()) {
383: prefix = "d_";
384: } else if (c.isOWLDataProperty() || c.isOWLObjectProperty()
385: || c.isOWLAnnotationProperty()) {
386: prefix = "p_";
387: } else if (c.isOWLNamedIndividual()) {
388: prefix = "i_";
389: }
390:
391: String id = prefix + validJavaIDForIRI(c.getIRI());
392:
393: while (voc.fields().keySet().contains("s_" + id)) {
394: id += "_A";
395: }
396:
397: final String sFieldName = "s_" + id;
398:
399: final JFieldVar fv1 = voc.field(JMod.PUBLIC | JMod.STATIC
400: | JMod.FINAL, String.class, sFieldName,
401: JExpr.lit(c.getIRI().toString()));
402: if (withOWLAPI) {
403: voc.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, IRI.class, id, cm
404: .ref(IRI.class).staticInvoke("create").arg(fv1));
405: }
406:
407: entities.put(c, voc.staticRef(fv1));
408: }
409: }
410:
411: private String javaClassId(OWLOntology ontology, OWLClass owlClass, ContextDefinition ctx) {
412: final Set<OWLAnnotation> annotations = owlClass.getAnnotations(ontology);
413: for (OWLAnnotation a : annotations) {
414: if (isValidJavaClassName(a, ctx)) {
415: if (a.getValue() instanceof OWLLiteral) {
416: return ((OWLLiteral) a.getValue()).getLiteral();
417: }
418: }
419: }
420: return validJavaIDForIRI(owlClass.getIRI());
421: }
422:
423: private JDefinedClass ensureCreated(final ContextDefinition ctx,
424: final String pkg, final JCodeModel cm, final OWLClass clazz,
425: final OWLOntology ontology) {
426: if (classes.containsKey(clazz)) {
427: return classes.get(clazz);
428: }
429:
430: JDefinedClass cls;
431:
432: String name = pkg + javaClassId(ontology, clazz, ctx);
433:
434: try {
435: cls = cm._class(name);
436:
437: cls.annotate(
438: cz.cvut.kbss.jopa.model.annotations.OWLClass.class)
439: .param("iri", entities.get(clazz));
440:
441: final JDocComment dc = cls.javadoc();
442: dc.add("This class was generated by the OWL2Java tool version " + VERSION);
443:
444: // if (clazz.equals(f.getOWLThing())) {
445: // RDFS label
446: final JClass ftLabel = cm.ref(String.class);
447: final JFieldVar fvLabel = addField("name", cls, ftLabel);
448: fvLabel.annotate(OWLAnnotationProperty.class).param("iri",
449: cm.ref(CommonVocabulary.class).staticRef("RDFS_LABEL"));
450:
451: // DC description
452: final JClass ftDescription = cm.ref(String.class);
453: final JFieldVar fvDescription = addField("description", cls, ftDescription);
454: fvDescription.annotate(OWLAnnotationProperty.class).param("iri",
455: cm.ref(CommonVocabulary.class).staticRef("DC_DESCRIPTION"));
456:
457: // @Types Set<String> types;
458: final JClass ftTypes = cm.ref(Set.class).narrow(String.class);
459: final JFieldVar fvTypes = addField("types", cls, ftTypes);
460: fvTypes.annotate(Types.class);
461:
462: // @Id public final String id;
463: final JClass ftId = cm.ref(String.class);
464: final JFieldVar fvId = addField("id", cls, ftId);
465: JAnnotationUse a = fvId.annotate(Id.class);
466:
467: a.param("generated", true);
468:
469: // @Properties public final Map<String,Set<String>> properties;
470: final JClass ftProperties = cm.ref(Map.class).narrow(
471: cm.ref(String.class),
472: cm.ref(Set.class).narrow(String.class));
473: final JFieldVar fvProperties = addField("properties", cls,
474: ftProperties);
475: fvProperties.annotate(Properties.class);
476: // }
477:
478: } catch (JClassAlreadyExistsException e) {
479: LOG.trace("Class already exists. Using the existing version. {}", e.getMessage());
480: cls = cm._getClass(name);
481: }
482: classes.put(clazz, cls);
483:
484: return cls;
485: }
486:
487: private boolean isValidJavaClassName(OWLAnnotation a, ContextDefinition ctx) {
488: // TODO Replace this hardcoded stuff with a configurable solution
489: return a.getProperty().getIRI()
490: .equals(IRI.create("http://krizik.felk.cvut.cz/ontologies/2009/ic.owl#javaClassName"));
491: // Annotation of annotation is currently not supported
492: // for (OWLAnnotation ctxAnn : a.getAnnotations()) {
493: // ctxAnn.getValue().accept(v);
494: // final String icContextName = v.getName();
495: // System.out.println("Context: " + icContextName);
496: // if (icContextName != null && icContextName.equals(ctx.name)) {
497: // return true;
498: // }
499: // }
500: }
501:
502: }